﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "StructureWallHoleCalculators.h"
#include "GbmpBuiltInParameterDefinitionsNew.h"
#include "GcmpBuiltInParameterDefinitions.h"
#include "IBaseGraphicsElementShapeComponent.h"
#include "IDocument.h"
#include "IDocumentManager.h"
#include "IElementOpening.h"
#include "IElementParameters.h"
#include "IExternalDataComponent.h"
#include "IFamilyConfigElement.h"
#include "IGraphicsArc.h"
#include "IGraphicsPoint.h"
#include "IInstance.h"
#include "IModelView.h"
#include "IParameter.h"
#include "IParameterDefinitionLibrary.h"
#include "IParameterValueCurveByPoints.h"
#include "ITransactionError.h"
#include "IType.h"
#include "LevelUtils.h"
#include "StructureBasicWall.h"
#include "StructureInstanceBuildingStoreyData.h"
#include "StructureInstanceLevelUtils.h"
#include "StructureVariableSectionWall.h"
#include "StructureWallHoleInput.h"

#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"




using namespace gcmp;



IMPLEMENT_CALCULATOR_CREATOR(gcmp, WallHoleAssociatedLevelCalculator);
IMPLEMENT_CALCULATOR_CREATOR(gcmp, WallHoleThicknessParameterCalculator);

void WallHoleThicknessParameterCalculator::ReportInputDataIds(std::vector<RegenDataId> & oInputDatas) const
{
    const IInstance* pElement = GetElement<IInstance>();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pElement, L"计算器的目标对象为空",L"GDMPLab",L"2024-03-30");

    ElementId wallId = pElement->GetHostElementId();
    if (!wallId.IsValid())
    {
        return;
    }

    //墙洞的Host主体依赖数据收集
    {
        const IInstance* pHostWallInstance = dynamic_cast<const IInstance*>(GetDocument()->GetElement(wallId));
        DBG_WARN_AND_RETURN_VOID_UNLESS(pHostWallInstance, L"pHostWallInstance为空",L"GDMPLab",L"2024-03-30");

        //直墙
        if (const IExternalDataComponent * pExternalDataComponent = pHostWallInstance->GetExternalDataComponent())
        {
            auto pData0 = pExternalDataComponent->FindExternalData(StructureBasicWall::GetStaticClassSchema()->GetName());
            if (pData0 != nullptr)
            {
                const StructureBasicWall* pWall = dynamic_cast<const StructureBasicWall*>(pData0);
                oInputDatas.push_back(pWall->GetWallShapeChangedRdId());
            }

            //变截面墙
            auto pData1 = pExternalDataComponent->FindExternalData(StructureVariableSectionWall::GetStaticClassSchema()->GetName());
            if (pData1 != nullptr)
            {
                const StructureVariableSectionWall* pWall = dynamic_cast<const StructureVariableSectionWall*>(pData1);
                oInputDatas.push_back(pWall->GetWallShapeChangedRdId());
            }
        }
    }

    //墙洞的实例依赖数据收集
    {
        oInputDatas.push_back(pElement->GetBasicInformation()->GetTypeIdRdId());
    }

    //墙洞的类型依赖数据收集
    {
        const IElementParameters* pElementParameters = pElement->GetBasicInformation()->GetType()->GetElementParameters();
        DBG_WARN_AND_RETURN_VOID_UNLESS(pElementParameters, L"参数行为为空",L"GDMPLab",L"2024-03-30");
        oInputDatas.push_back(pElementParameters->GetDriveParameterRdId());
    }
}

void WallHoleThicknessParameterCalculator::Execute()
{
    IElement* pElement = GetTarget();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pElement, L"无效参数",L"GDMPLab",L"2024-03-30");

    WallHoleThicknessParameterCalculator::UpdateWallHoleThicknessParameters(pElement);
}

bool WallHoleThicknessParameterCalculator::UpdateWallHoleThicknessParameters(IElement *pElement)
{
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pElement, L"pElement为空",L"GDMPLab",L"2024-03-30");
    IInstance* pHole = quick_cast<IInstance>(pElement);
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pHole, L"pInstance为空",L"GDMPLab",L"2024-03-30");

    IDocument* pDoc = pHole->GetDocument();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pDoc, L"pDoc为空",L"GDMPLab",L"2024-03-30");

    const IInstance* pHost = dynamic_cast<IInstance*>(pDoc->GetElement(pHole->GetHostInstanceId()));
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pHost, L"pHost为空",L"GDMPLab",L"2024-03-30");

    const IElementBasicInformation* pBasicInfo = pHost->GetBasicInformation();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pBasicInfo, L"pBasicInfo为空",L"GDMPLab",L"2024-03-30");

    const IType* pHostType = pBasicInfo->GetType();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pHostType, L"pHostType为空",L"GDMPLab",L"2024-03-30");

    OwnerPtr<IParameter> hostThicknessParam = ELEMENT_PARAMETER(pHostType, CoreThicknessBuiltInParameter);
    DBG_WARN_AND_RETURN_FALSE_UNLESS(IParameter::IsValidParameter(hostThicknessParam), L"hostThicknessParam无效",L"GDMPLab",L"2024-03-30");

    double hostThickness = hostThicknessParam->GetValueAsDouble();
    double holeThickness = hostThickness;

    OwnerPtr<IParameter> hostCoordsParam = ELEMENT_PARAMETER(pHost, CoordinateSystemBuiltInParameter);
    DBG_WARN_AND_RETURN_FALSE_UNLESS(IParameter::IsValidParameter(hostCoordsParam), L"hostCoordsParam无效",L"GDMPLab",L"2024-03-30");
    IParameterValueCurveByPoints* pCurveInfo = 
        dynamic_cast<IParameterValueCurveByPoints*>(hostCoordsParam->GetParameterValueStorageFw());
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pCurveInfo, L"pCurveInfo为空",L"GDMPLab",L"2024-03-30");

    const std::vector<OwnerPtr<IGraphicsCurve3d>> curves = pCurveInfo->GenerateCurve();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(curves.size() != 0, L"curves无效",L"GDMPLab",L"2024-03-30");

    const IGraphicsArc* pArc = dynamic_cast<const IGraphicsArc*>(curves[0].get());
    if (pArc)
    {
        double radius = pArc->GetRadius();

        OwnerPtr<IParameter> holeWidthParam = ELEMENT_PARAMETER(pHole->GetBasicInformation()->GetType(), RectSectionWidthBuiltInParameter);
        DBG_WARN_AND_RETURN_FALSE_UNLESS(IParameter::IsValidParameter(holeWidthParam), L"holeWidthParam无效",L"GDMPLab",L"2024-03-30");
        double holeWidth = holeWidthParam->GetValueAsDouble();

        double OB = radius - hostThickness * 0.5;
        double AB = holeWidth * 0.5;
        double delta = 0.0;
        if (MathUtils::IsGreaterThan(OB, AB, Constants::LENGTH_EPS))
        {
            double OA = std::sqrt(OB * OB - AB * AB);
            delta = radius - hostThickness * 0.5 - OA;
        }
        else
        {
            delta = radius - hostThickness * 0.5;
        }
        DBG_WARN_AND_RETURN_FALSE_UNLESS(MathUtils::IsGreaterThan(delta, 0, Constants::LENGTH_EPS), L"delta无效",L"GDMPLab",L"2024-03-30");

        holeThickness += delta * 2;
    }

    OwnerPtr<IParameter> holeThicknessParam = ELEMENT_PARAMETER(pHole, WallHoleThicknessBuiltInParameter);
    DBG_WARN_AND_RETURN_FALSE_UNLESS(IParameter::IsValidParameter(holeThicknessParam), L"holeThicknessParam无效",L"GDMPLab",L"2024-03-30");
    holeThicknessParam->SetValueAsDouble(holeThickness);
    pHole->GetElementParameters()->SetParameter(holeThicknessParam.get());

    return true;
}

void WallHoleAssociatedLevelCalculator::ReportInputDataIds(std::vector<RegenDataId> & oInputDatas) const
{
    const IInstance* pElement = GetElement<IInstance>();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pElement, L"计算器的目标对象为空",L"GDMPLab",L"2024-03-30");

    ElementId wallId = pElement->GetHostElementId();
    if (!wallId.IsValid())
    {
        return;
    }

    //墙洞的Host主体依赖数据收集
    {
        const IInstance* pHostWallInstance = quick_cast<const IInstance>(GetDocument()->GetElement(wallId));
        DBG_WARN_AND_RETURN_VOID_UNLESS(pHostWallInstance, L"pHostWallInstance为空",L"GDMPLab",L"2024-03-30");
        const IStructureInstanceBuildingStoreyData* pWallStoreyData = IStructureInstanceBuildingStoreyData::Get(pHostWallInstance);
        DBG_WARN_AND_RETURN_VOID_UNLESS(pWallStoreyData, L"pWallStoreyData为空",L"GDMPLab",L"2024-03-30");
        RegenDataId wallStoreyDataId = pWallStoreyData->GetBuildingStoreyIdRdId();
        oInputDatas.push_back(wallStoreyDataId);
    }
}

void WallHoleAssociatedLevelCalculator::Execute()
{
    const IInstance* pWallHoleInstance = GetElement<IInstance>();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pWallHoleInstance, L"计算器的目标对象为空",L"GDMPLab",L"2024-03-30");

    ElementId wallId = pWallHoleInstance->GetHostElementId();
    DBG_WARN_AND_RETURN_VOID_UNLESS(wallId.IsValid(), L"计算器的目标对象为空",L"GDMPLab",L"2024-03-30");

    const IInstance* pHostWallInstance = quick_cast<const IInstance>(GetDocument()->GetElement(wallId));
    DBG_WARN_AND_RETURN_VOID_UNLESS(pHostWallInstance, L"pHostWallInstance为空",L"GDMPLab",L"2024-03-30");

    OwnerPtr<IParameter> wallLevelParam = ELEMENT_PARAMETER(pHostWallInstance, BuildingStoreyBuiltInParameter);
    DBG_WARN_AND_RETURN_VOID_UNLESS(IParameter::IsValidParameter(wallLevelParam), L"wallLevelParam无效",L"GDMPLab",L"2024-03-30");
    ElementId wallLevelId = wallLevelParam->GetValueAsElementId();

    bool status = StructureInstanceLevelUtils::SetInstanceStoreyLevel(GetDocument(), pWallHoleInstance->GetElementId(), wallLevelId);
    DBG_WARN_AND_RETURN_VOID_UNLESS(status, L"设置所属楼层失败",L"GDMPLab",L"2024-03-30");
}

